package com.mbf.crm.controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.mbf.crm.handler.WebSocketHandler;
import com.mbf.crm.model.dao.ResourceDao;
import com.mbf.crm.model.dao.RoleDao;

import org.apache.commons.codec.digest.DigestUtils;
import org.jboss.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mbf.crm.common.AjaxResult;
import com.mbf.crm.common.Constants;
import com.mbf.crm.common.SocketMessage;
import com.mbf.crm.common.VerifyCodeUtils;
import com.mbf.crm.model.dao.MemberDao;
import com.mbf.crm.model.domain.Member;
import com.mbf.crm.model.domain.Resource;
import com.mbf.crm.model.domain.Role;
import com.mbf.crm.model.enums.Gender;
import com.mbf.crm.model.enums.ResourceType;
import com.mbf.crm.service.AttachmentService;


/**
 * 系统的入口控制器，入口控制器里面的请求，理论上都受权限控制
 * @author 晏鼠  张劲松
 *
 */
@Controller
@Transactional(readOnly = true)
//指定事务是否为只读事务，默认值为 false；为了忽略那些不需要事务的方法，比如读取数据，可以设置 read-only 为 true。
public class AppController {

	Logger logger = Logger.getLogger(AppController.class);
	
	@Autowired
	private MemberDao memberDao;
	
	@Autowired
	private RoleDao roleDao;
	
	@Autowired
	private ResourceDao resourceDao;
	
	@Value("${crm.system.super-user-id}")
	Long superUserid;
	
	@Autowired
	private WebSocketHandler webSocketHandler;
	
	@Autowired
	private AttachmentService attachmentService;
	
	@RequestMapping("/")
	public String index(){
		return "index";
	}
	
	@RequestMapping("/login")
	public String login(HttpSession session){
		if(session.getAttribute(Constants.SESSION_MEMBER_KEY) != null){
			//"redirect:/"表示转发到首页
			return "redirect:/";
		}
		return "login";
	}
	
	@RequestMapping("/logout")
	public String logout(HttpSession session){
		//注销用户，使用户失效
		session.invalidate();
		return "redirect:/login";
	}
	
	@RequestMapping(value="/login",method = RequestMethod.POST)
	public String login(String userName,String password,RedirectAttributes attributes,HttpSession session){
		//参数校验
		if(StringUtils.isEmpty(userName) || StringUtils.isEmpty(password)){
			attributes.addFlashAttribute("error", "参数出错");
			return "redirect:/login";
		}
		Member member = memberDao.findByUserName(userName);
		//校验密码
		if(member == null || !member.getStatus()){
			attributes.addFlashAttribute("error", "用户不存在或被禁用");
			return "redirect:/login";
		}else if(!member.getPassword().equals(DigestUtils.sha256Hex(password))){
			attributes.addFlashAttribute("error", "用户名或密码出错");
			return "redirect:/login";
		}
		//这是一个用户在一个客户端进行登陆后。在另一个地方进行登录，要进行判断，
		//如果用户在线要先下线
		if(webSocketHandler.isOnline(member.getId())){
			//通知下线
			webSocketHandler.sendMessageToUser(member.getId(),new SocketMessage("logout","").toTextMessage());
			webSocketHandler.offLine(member.getId());
		}
		final List<Resource> allResources;
		//获取用户可用菜单，所有有权限的请求，所有资源key
		List<Role> roles = member.getRoles();
		List<Resource> menus = new ArrayList<Resource>();
		Set<String> urls = new HashSet<String>();
		Set<String> resourceKey = new HashSet<String>();
		if(superUserid == member.getId()){
			//超级管理员，直接获取所有权限资源
			allResources = resourceDao.findByStatus(true, new Sort(Direction.DESC,"weight"));
		}else{
			allResources = new ArrayList<Resource>();
			//forEach jdk1.8才支持
			roles.forEach(t -> allResources.addAll(t.getResource()));
		}
		for (Resource t : allResources) {
			//可用菜单
			if(t.getResType().equals(ResourceType.MENU)){
				menus.add(t);
			}
			
			//所有请求资源
			if(!StringUtils.isEmpty(t.getFunUrls())){
				urls.add(t.getMenuUrl());
			}
			String[] funUrls = t.getFunUrls().split(",");
			for (String url : funUrls) {
				if(!StringUtils.isEmpty(url)){
					urls.add(url);
				}
			}
			//资源key
			resourceKey.add(t.getResKey());
		}
		//将用户可用菜单和权限存入session
		session.setAttribute("menus", menus);
		session.setAttribute("urls", urls);
		session.setAttribute("resourceKey", resourceKey);
		session.setAttribute(Constants.SESSION_MEMBER_KEY, member);
		//是否是管理员
		session.setAttribute("isSuper", superUserid == member.getId());
		return "redirect:/";
	}
	
	/**
	 * 注册
	 * @return
	 */
	@RequestMapping(value="/reg",method = RequestMethod.GET)
	public String toReg(){
		return "reg";
	}
	
	/**
	 * 注册表单验证
	 * @return
	 */
	@RequestMapping(value = "/reg",method = RequestMethod.POST)
	@Transactional
	public String doReg(String realName,String userName,String password,String code,@SessionAttribute(Constants.SESSION_VERIFY_CODE_KEY) String verifyCode,RedirectAttributes attributes){
		if(StringUtils.isEmpty(code)){
			/**
			 * addFlashAttribute说明：
			 * addFlashAttribute是为了防止表单重新提交的一个类
			 */
			attributes.addFlashAttribute("error","验证码不能为空");
		}else if(!code.equalsIgnoreCase(verifyCode)){
			attributes.addFlashAttribute("error", "验证码错误");
		}else if(StringUtils.isEmpty(realName)){
			attributes.addFlashAttribute("error", "姓名不能为空");
		}else if(StringUtils.isEmpty(userName)){
			attributes.addFlashAttribute("error", "账号不能为空");
		}else if(StringUtils.isEmpty(password)){
			attributes.addFlashAttribute("error", "密码不能为空");
		}else if(password.length() < 6){
			attributes.addFlashAttribute("error", "密码长度不能小于6位");
		}else if(memberDao.findByUserName(userName) != null){
			attributes.addFlashAttribute("error", "此账号已存在！");
		}
		if(attributes.getFlashAttributes().size() > 0){
			return "redirect:/reg";
		}else{
			Member member = new Member();
			member.setRealName(realName);
			member.setGender(Gender.BOY);
			member.setUserName(userName);
			//spring框架自带DigestUtils加密算法类
			member.setPassword(DigestUtils.sha256Hex(password));
			member.setTelephone(userName);
			member.setEmail(userName+"@qq.com");
			member.setHiredate(new Date());
			member.setStatus(true);
			List<Role> roles = new ArrayList<Role>();
			roles.add(roleDao.findOne(3l));
			member.setRoles(roles);
			memberDao.save(member);
		}
		return "login";
	}
	
	
	/**
	 * 权限resource的js资源
	 * @param session
	 * @param model
	 * @return 
	 */
	@RequestMapping("/resource")
	public String login(HttpSession session,Model model){
		ObjectMapper mapper = new ObjectMapper();
		Object resourceKey = session.getAttribute("resourceKey");
		try{
			model.addAttribute("resourceKey",mapper.writeValueAsString(resourceKey));
		}catch(JsonProcessingException e){
			logger.error("json转换错误",e);
		}
		return "resource";
	}
	
	/**
	 * 验证码
	 * @param response
	 * @param session
	 */
	@RequestMapping(value="/verify/code",method = RequestMethod.GET)
	public void verifyCode(HttpServletResponse response,HttpSession session){
		try {
			String code = VerifyCodeUtils.outputVerifyImage(150, 50, response.getOutputStream(), 4);
			session.setAttribute(Constants.SESSION_VERIFY_CODE_KEY, code);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 首页
	 * @return
	 */
	@RequestMapping("/desktop")
	public String desktop(){
		return "desktop";
	}
	
	/**
	 * 请求权限被拒绝的提醒页面
	 * @return
	 */
	@RequestMapping("/reject")
	public String reject(){
		return "reject";
	}
	
	@RequestMapping("/change/info")
	public String changeinfo(@SessionAttribute("s_member") Member smember){
		return "info";
	}
	
	
	@RequestMapping(method = RequestMethod.POST,value = "/change/info")
	@Transactional
	@ResponseBody
	public AjaxResult doChangeInfo(@SessionAttribute("s_member") Member smember,Member member,HttpSession session){
		System.out.println("----------"+member);
		if(StringUtils.isEmpty(member.getRealName()) || StringUtils.isEmpty(member.getTelephone()) || StringUtils.isEmpty(member.getEmail()) || member.getGender() == null){
			return new AjaxResult(false).setMessage("参数错误");
		}
		smember.setRealName(member.getRealName());
		smember.setGender(member.getGender());
		smember.setTelephone(member.getTelephone());
		smember.setEmail(member.getEmail());
		smember.setAvatar(member.getAvatar());
		memberDao.save(smember);
		//清理工作
		//清除用户无用图像
		attachmentService.clearAvatar(smember);
		session.setAttribute("s_member", smember);
		return new AjaxResult();
		
	}
	
	
}
